package com.zhouchj.elasticsearch.query;

import com.zhouchj.elasticsearch.basic.EsQueryBuilderUtil;
import com.zhouchj.elasticsearch.basic.SFunction;
import com.zhouchj.elasticsearch.constant.EsConstant;
import com.zhouchj.elasticsearch.model.page.PageForm;
import com.zhouchj.elasticsearch.model.page.QueryPageEntity;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.List;
import java.util.stream.Collectors;

/**
 * ES链式查询
 * 封装{@link EsQueryBuilderUtil}
 *
 * @author zhouchj
 * @date 2023/8/18
 */
@Slf4j
public class EsLambdaQueryChainWrapper<T> extends EsAggQuery<T, SFunction<T, ?>, EsLambdaQueryChainWrapper<T>> {


    /**
     * 排序(默认不排序)
     */
    private Sort sort = Sort.unsorted();

    /**
     * 分页
     */
    private PageForm pageForm = new PageForm();


    public EsLambdaQueryChainWrapper(IndexCoordinates index,
                                     Class<T> clazz,
                                     ElasticsearchRestTemplate elasticsearchRestTemplate) {
        super(clazz, index, elasticsearchRestTemplate);
    }


    /**
     * 设置分页信息
     *
     * @param pageForm 分页信息
     * @return this
     */
    public EsLambdaQueryChainWrapper<T> withPage(PageForm pageForm) {
        this.pageForm = pageForm;
        return this;
    }

    /**
     * 设置排序信息
     *
     * @param func 字段
     * @return this
     */
    public EsLambdaQueryChainWrapper<T> withSort(Sort.Direction direction, SFunction<T, ?> func) {
        String fieldName = this.convertToEsFieldName(clazz, func);
        this.sort = Sort.by(direction, fieldName);
        return this;
    }


    /**
     * 设置排序信息
     *
     * @param sort 排序信息
     * @return this
     */
    public EsLambdaQueryChainWrapper<T> withSort(Sort sort) {
        this.sort = sort;
        return this;
    }


    /**
     * 获取分页信息(终止操作)
     *
     * @return 分页信息
     */
    public QueryPageEntity<T> page() {
        EsQueryBuilderUtil.buildPage(builder, pageForm, sort);
        builder.withQuery(boolQueryBuilder);
        SearchHits<T> search = elasticsearchRestTemplate.search(builder.build(), clazz, index);
        QueryPageEntity<T> pageEntity = EsQueryBuilderUtil.buildPageEntity(search, pageForm);
        clear();
        return pageEntity;
    }

    /**
     * 查询符合查询条件的所有信息(终止操作)
     *
     * @return list
     */
    public List<T> list() {
        return this.searchHit()
                .stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }

    /**
     * 查询符合查询条件的信息数量(终止操作)
     *
     * @return 数量
     */
    public long count() {
        builder.withQuery(boolQueryBuilder);
        long count = elasticsearchRestTemplate.count(builder.build(), clazz, index);
        clear();
        return count;
    }

    /**
     * 拿到原生SearchHits(终止操作)
     * 不带分页
     *
     * @return SearchHits
     */
    public SearchHits<T> searchHit() {
        builder.withQuery(boolQueryBuilder);
        builder.withPageable(PageRequest.of(0, EsConstant.MAX_RESULT_WINDOW, sort));
        SearchHits<T> searchHits = elasticsearchRestTemplate.search(builder.build(), clazz, index);
        clear();
        return searchHits;
    }

    /**
     * 获取查询条件，不进行操作
     *
     * @return query
     */
    public NativeSearchQueryBuilder getQueryBuilder() {
        EsQueryBuilderUtil.buildPage(builder, pageForm, sort);
        builder.withQuery(boolQueryBuilder);
        return builder;
    }

    /**
     * 清除数据，让该类可以重复利用
     */
    public void clear() {
        boolQueryBuilder = new BoolQueryBuilder();
        builder = new NativeSearchQueryBuilder();
        pageForm = new PageForm();
        sort = Sort.unsorted();
    }


}
